package code.example.base.util.concurrent.lock.countdownlatch;

import code.example.tool.LogFactory;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class ICountDownLatchReentrantlock implements ICountDownLatch {
    ReentrantLock lock = new ReentrantLock();
    Condition condition =  lock.newCondition();
    int count ;
    public ICountDownLatchReentrantlock(int count){
       this.count = count;
    }

    @Override
    public void countdown() {
        lock.lock();
        try {
            count--;
            LogFactory.getLog().info("countdown:"+Thread.currentThread().getName()+" :count down :"+count);
            if(count ==0){
                condition.signalAll();
                LogFactory.getLog().info(Thread.currentThread().getName()+" :to wake up");
            }
        }finally {
            lock.unlock();
        }
    }

    @Override
    public void await() {
        await(0,TimeUnit.SECONDS);
    }

    @Override
    public boolean await(int timeout, TimeUnit timeUnit) {
        long mills = timeUnit.toMillis(timeout);
        long endTimeMill = System.currentTimeMillis()+mills;
        lock.lock();
        try {
            for(;;){
                long  timeoutReal =endTimeMill - System.currentTimeMillis() ;
                if(count ==0){
                   return true;
                }else if(timeout <=0){
                    try {
                        LogFactory.getLog().info("await :to block thread: to park thread: "+Thread.currentThread().getName());
                        condition.await();
                    }catch (InterruptedException e){};
                }else if(timeoutReal<=0){
                    return false;
                }else{
                    try {
                        LogFactory.getLog().info("await :to block thread: to park thread: "+Thread.currentThread().getName());
                        condition.await(timeoutReal,TimeUnit.MILLISECONDS);
                    }catch (InterruptedException ee){}
                }
            }

        }finally {
            lock.unlock();
        }


    }
}
